//============================================================================
// Name        : HelloRaspberryPi.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#define _POSIX_SOURCE	1

#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

#include <linux/input.h>
#include <linux/joystick.h>

#include "usb.h"

#include "RPi_JoyStick.h"

// グローバル変数。
const unsigned char HID_REPORT_SET		= 0x09;
const unsigned char BULK_OUT			= 0x02;
const unsigned short MISSILE_VENDER_ID		= 0x2123;
const unsigned short MISSILE_PRODUCT_ID	= 0x1010;
const unsigned char MISSILE_CMD_HEADER	= 0x02;
const unsigned char MISSILE_CMD_DOWN	= 0x01;
const unsigned char MISSILE_CMD_UP		= 0x02;
const unsigned char MISSILE_CMD_LEFT	= 0x04;
const unsigned char MISSILE_CMD_RIGHT	= 0x08;
const unsigned char MISSILE_CMD_FIRE	= 0x10;
const unsigned char MISSILE_CMD_STOP	= 0x20;
const int USB_TIMEOUT = 3000;
const int USB_BUF_SIZE = 8;

unsigned long sync_usec = 10 * 1000;

int main() {

	struct usb_bus *usb_bus;
	struct usb_device *usb_dev;
	usb_dev_handle *usb_hndl;
	struct usb_config_descriptor *config;
	struct usb_interface *interface;
	struct usb_interface_descriptor *altsetting;
	unsigned char usb_buf[USB_BUF_SIZE];
	char *js_dev = "/dev/input/js0";
	int js_fd;
	struct js_event js_ev;
	unsigned char axes = 2;
	unsigned char buttons = 2;
	int *axis;
	char *button;
	struct timeval tv;
	unsigned long start_usec;
	unsigned long end_usec;
	unsigned long use_usec;
	int i;


	// 変数初期化。
	for (i = 0; i < USB_BUF_SIZE; i++)
		usb_buf[i] = 0x00;

	// ジョイスティックの初期化。
	js_fd = JOYSTICK_open(js_dev);
	axis = calloc(axes, sizeof(int));
	button = calloc(buttons, sizeof(char));

	// USB初期化。
	usb_init();
	usb_find_busses();
	usb_find_devices();

	// USBデバイスチェック。
	for (usb_bus = usb_get_busses(); usb_bus; usb_bus = usb_bus->next)
	{
		for (usb_dev = usb_bus->devices; usb_dev; usb_dev = usb_dev->next)
		{
			if ((usb_dev->descriptor.idVendor == MISSILE_VENDER_ID) &&
					(usb_dev->descriptor.idProduct == MISSILE_PRODUCT_ID))
			{
				// デバイスオープン。
				if ((usb_hndl = usb_open(usb_dev)) == NULL)
				{
					// オープンに失敗。
					printf("usb_open Error.(%s)\n", usb_strerror());
					exit(-1);
				}

				printf("found usb missile launcher\n");

				config = &usb_dev->config[0];
				interface = &config->interface[0];
				altsetting = &interface->altsetting[0];

				if (usb_set_configuration(usb_hndl, config->bConfigurationValue) < 0)
				{
					if (usb_detach_kernel_driver_np(usb_hndl,
							altsetting->bInterfaceNumber) < 0)
					{
						printf("usb_set_configration() error.\n");
						usb_close(usb_hndl);
						return(-1);
					}
				}

				// インタフェースの使用をシステムに通知。
				if (usb_claim_interface(usb_hndl, altsetting->bInterfaceNumber) < 0)
				{
					// インタフェースの使用要求でエラー。
					printf("claiming interface error\n");
				}
				else
				{
					while(1)	// メインループ
					{
						gettimeofday(&tv, NULL);
						start_usec = tv.tv_sec * 1000 * 1000 + tv.tv_usec;

						// ジョイスティックの操作値を取得。
						if (JOYSTICK_read(&js_ev, js_fd) > 0)
						{
							switch(js_ev.type & ~JS_EVENT_INIT)
							{
								case JS_EVENT_BUTTON:
									button[js_ev.number] = js_ev.value;
									break;
								case JS_EVENT_AXIS:
									axis[js_ev.number] = js_ev.value;
									break;
							}
							// 送信データ構成。
							usb_buf[0] = MISSILE_CMD_HEADER;
							// コマンド部。
							usb_buf[1] = 0x00;
							if (axis[0] > 10000)
							{
								/// 右回転コマンド。
								usb_buf[1] |= MISSILE_CMD_RIGHT;
							}
							else if (axis[0] < -10000)
							{
								/// 左回転コマンド。
								usb_buf[1] |= MISSILE_CMD_LEFT;
							}
							if (axis[1] < -10000)
							{
								/// 上回転コマンド。
								usb_buf[1] |= MISSILE_CMD_UP;
							}
							else if (axis[1] > 10000)
							{
								/// 下回転コマンド。
								usb_buf[1] |= MISSILE_CMD_DOWN;
							}

							if (axis[3] < -10000)
							{
								usb_buf[1] = MISSILE_CMD_FIRE;
							}

							if (usb_buf[1] == 0x00)
								usb_buf[1] = MISSILE_CMD_STOP;

							// USBへ送信。
							if (usb_control_msg(
									usb_hndl,
									USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
									HID_REPORT_SET,
									0,
									0,
									(char*)usb_buf,
									sizeof(usb_buf),
									USB_TIMEOUT) < 0)
							{
								printf("usb write error.\n");
							}
						}

						gettimeofday(&tv, NULL);
						end_usec = tv.tv_sec * 1000 * 1000 + tv.tv_usec;
						use_usec = end_usec - start_usec;

						if (sync_usec > use_usec)
							usleep(sync_usec -use_usec);

					}	// メインループ終端。

					// USBインタフェースの解放とデバイスクローズ。
					usb_release_interface(usb_hndl, 0);
					usb_close(usb_hndl);

					// ジョイスティックの開放。
					JOYSTICK_close(js_fd);
				}
			}
		}
	}


	return 0;
}
